package com.btcode.common;

import com.btcode.exception.MsgException;
import com.btcode.log.ILog;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Properties;

/**
 * <pre>
 * 读取Properties的工具类
 * 常规用法，通过setPropertiesBasePath方法，设置配置文件的目录，再调用getValue(String propertiesName, String keyName)获取属性,
 * 		这个过程，是根据propertiesName和PropertiesBasePath构造配置文件的路径，加载配置文件，并读取配置信息。
 *
 * 便捷用法，设置setPropertiesPath，设置默认的具体的配置文件路径，在调用getValue(String keyName)，获取属性
 * 		这个过程是这个时候，其实是把文件路径的目录设置为PropertiesBasePath，而把文件名设置为defaultPropertiesName
 * 		在调用getValue(String keyName)时，内部是调用getValue(String propertiesName, String keyName)
 * <pre>
 * @author Administrator
 */
public class PropertiesUnit {

    //配置文件根目录
    private static String basePath;
    // 配置文件路径
    private static String defaultpropertiesName = "output";
    // 映射配置缓存
    private static HashMap<String, HashMap<String, String>> maps = new HashMap<String, HashMap<String, String>>();

    private static ILog log;

    private static HashMap<String, Properties> propertiesMap = new HashMap<String, Properties>();
    private static HashMap<String, Object[]> keysMap = new HashMap<String, Object[]>();

    @SuppressWarnings("rawtypes")
    private static Class loadPathClass;

    public static void setPropertiesPath(String propertiesPath) {
        File propertiesFile = new File(propertiesPath);
        String fileName = propertiesFile.getName();
        PropertiesUnit.defaultpropertiesName = fileName.substring(0, fileName.lastIndexOf("."));
        PropertiesUnit.basePath = propertiesFile.getParent();
    }

    @SuppressWarnings("rawtypes")
    public static void init(Class loadPathClass) {
        PropertiesUnit.loadPathClass = loadPathClass;
    }

    public static ILog getLog() {
        return log;
    }

    public static void setLog(ILog log) {
        PropertiesUnit.log = log;
    }

    /**
     * 获取配置信息,先在config目录中找名称为output，拓展名为properties的配置文件，如果找不到，就到classPath中找 gislin 2016年7月21日
     */
    public static String getValue(String name) {
        String value = getValue(defaultpropertiesName, name);
        return value;
    }

    /**
     * 获取配置信息 gislin 2016年7月21日
     *
     * @param propertiesName 配置名称，先在config目录中找名称为"propertiesName"，拓展名为properties的配置文件，如果找不到，就到classPath中找
     * @param keyName 配置key
     */
    public static String getValue(String propertiesName, String keyName) {
        if(propertiesName == null || propertiesName.trim().equals("")){
            propertiesName = defaultpropertiesName;
        }
        if (!propertiesMap.containsKey(propertiesName) || propertiesMap.get(propertiesName)
            == null) {
            propertiesMap.put(propertiesName, loadProperties(propertiesName));
            keysMap.put(propertiesName,
                        Collections.list(propertiesMap.get(propertiesName).propertyNames())
                            .toArray());
        }
        String value = propertiesMap.get(propertiesName).getProperty(keyName);

        return value;
    }

    public static int getInt(String name) {
        String value = null;
        int reault = -1;
        value = getValue(name);
        try {
            reault = Integer.parseInt(value);
        }
        catch (Exception e) {
            e.printStackTrace();
            return Integer.MIN_VALUE;
        }

        return reault;
    }

    public static Boolean getBoolean(String name) {
        return getBoolean(null,name);
    }

    public static int getInt(String propertiesName, String name) {
        String value = null;
        int reault = -1;
        value = getValue(propertiesName, name);
        try {
            reault = Integer.parseInt(value);
        }
        catch (Exception e) {
            e.printStackTrace();
            return Integer.MIN_VALUE;
        }

        return reault;
    }

    public static Boolean getBoolean(String propertiesName, String name) {
        String value = getValue(propertiesName, name);
        if (value == null) {
            return null;
        }

        value = value.toLowerCase();

        if (value.equals("true")) {
            return true;
        }
        else if (value.equals("false")) {
            return false;
        }
        else {
            return null;
        }
    }

    /**
     * 拿到默认位置的mapping文件（config/output.mapping）
     *
     * @param name mapping文件::开头的某个键
     */
    public static HashMap<String, String> getMap(String name) {
        if (maps.size() == 0) {
            initMap(maps, null);
        }
        return maps.get(name);
    }

    /**
     * 获取指定位置的自定义mapping文件所有Map的Map
     *
     * @param mapFilePath 自定义mapping文件路径
     */
    public static HashMap<String, HashMap<String, String>> getAllMaps(String mapFilePath) {
        //用于重复性的加载各种mapping文件，无需缓存
        HashMap<String, HashMap<String, String>> fileMaps = new HashMap<String, HashMap<String, String>>();
        initMap(fileMaps, mapFilePath);
        return fileMaps;
    }

    /**
     * 获取Properties对象，配置文件放到class的根目录下即可
     */
    private static Properties loadProperties(String propertiesName) {
        //获取存放Properties文件的目录
        InputStream in = null;
        InputStreamReader inputStreamReader = null;
        Properties p = new Properties();
        try {
            if(basePath == null){
                throw new MsgException("basePath为空，无法获取配置");
            }
            in = new FileInputStream(basePath + "/" + propertiesName + ".properties");
            inputStreamReader = new InputStreamReader(in, "utf-8");
            p.load(inputStreamReader);//解决中文乱码问题
        }
        catch (IOException e) {

            if (log != null) {
                log.error("配置文件不存在：" +basePath + "/" + propertiesName + ".properties",
                          e);
            }

            System.err.println("配置文件不存在：" +basePath + "/" + propertiesName + ".properties");
            e.printStackTrace();
        }
        finally {
            try {
                if (in != null) {
                    in.close();
                }

                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
        return p;
    }

    /**
     * 获取Properties文件所有的键值
     *
     * @param propertiesName Properties文件路径
     */
    public static Object[] getPropertiesKeys(String propertiesName) {
        String prePropertiesPath = defaultpropertiesName;
        if (new File(propertiesName).exists()) {
            setPropertiesPath(propertiesName);
        }
        if (!propertiesMap.containsKey(propertiesName) || propertiesMap.get(propertiesName)
            == null) {
            Properties properties = loadProperties(propertiesName);
            propertiesMap.put(propertiesName, properties);
            keysMap.put(propertiesName,
                        Collections.list(propertiesMap.get(propertiesName).propertyNames())
                            .toArray());
        }
        Object[] value = keysMap.get(propertiesName);

        setPropertiesPath(prePropertiesPath);
        return value;
    }

    /**
     * 初始化自定义mapping文件
     *
     * @param maps 要被初始化的Map
     * @param mapPath mapping文件名
     */
    public static void initMap(HashMap<String, HashMap<String, String>> maps, String mapPath) {
        System.out.println("开始解析mapping映射文件");

        if (loadPathClass == null) {
            loadPathClass = PropertiesUnit.class;
        }

        InputStream in = null;
        if (mapPath == null || mapPath.equals("")) {
            String configBasePath = getConfigBasePath();
            String mappingPath = configBasePath + "/output.mapping";
            try {
                in = new FileInputStream(mappingPath);
            }
            catch (FileNotFoundException e) {
                System.out.println("从mapPath：" + mappingPath + "获取映射文件失败");
                e.printStackTrace();
                return;
            }
            System.out.println("从mappingPath:" + mappingPath + "中读取配置mapping信息");
        }
        else {
            try {
                in = new BufferedInputStream(new FileInputStream(mapPath));
            }
            catch (FileNotFoundException e) {
                System.out.println("从mapPath：" + mapPath + "获取映射文件失败");
                return;
            }
        }

        InputStreamReader inputStreamReader = null;
        BufferedReader bufferReader = null;
        HashMap<String, String> currentMap = null;
        String currentName = null;

        try {
            inputStreamReader = new InputStreamReader(in,"UTF-8");
            bufferReader = new BufferedReader(inputStreamReader);
            for (String line = bufferReader.readLine(); line != null; line = bufferReader.readLine()) {
                String[] lineInfo = line.split("//");
                String realLine = lineInfo[0].trim();

                if (realLine.trim().equals("")) {
                    continue;
                }

                if (realLine.startsWith("::")) {
                    currentMap = new HashMap<String, String>();
                    currentName = realLine.replaceFirst("::", "").trim();
                    maps.put(currentName, currentMap);
                }
                else if (currentMap != null) {
                    String[] mapInfo = realLine.trim().split("=");
                    if (mapInfo.length == 2) {
                        currentMap.put(mapInfo[0].trim(), mapInfo[1].trim());
                    }
                }
            }
        }
        catch (Exception e) {
            System.out.println("解析映射mapping文件出错，" + ExecptionUtil.getStackTrace(e));
        }
        finally {
            try {
                if(bufferReader != null){
                    bufferReader.close();
                }
                if(inputStreamReader != null){
                    inputStreamReader.close();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取配置文件的根目录 gislin 2017年4月20日
     */
    private static String getConfigBasePath() {
        if (basePath != null) {
            return basePath;
        }
        if (loadPathClass == null) {
            loadPathClass = PropertiesUnit.class;
        }
        //        String classPath = loadPathClass.getProtectionDomain().getCodeSource().getLocation().getFile();
        //        File classPathDir = new File(classPath).getParentFile();
        //
        //        String configPath = classPathDir.getParent() + "/config/";

        String configPath = System.getProperty("user.dir") + "/config/";//用户运行时上下文路径
        return configPath;
    }

    public static String getPropertiesPath() {
        String path = "";
        if (defaultpropertiesName == null || defaultpropertiesName.equals("")) {
            path = PropertiesUnit.class.getClassLoader().getResource("output.properties").getPath();
        }
        else {
            path = basePath + "/" + defaultpropertiesName+".properties";
        }
        return path;
    }

    public static void setValue(String key, String value) {
        Properties p = loadProperties(defaultpropertiesName);
        p.setProperty(key, value);
        String propertiesPath = getPropertiesPath();
        OutputStream out = null;

        try {
            out = new FileOutputStream(propertiesPath);
            p.store(out, null);
        }
        catch (Exception e) {
            e.printStackTrace();
            System.out.println("设置值出错:"+e.getMessage());
        }
        finally {
            try{
                if(out != null){
                    out.close();
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }

        }
    }
}
